//@ts-nocheck

//更新队列
import {isFunction} from './util';
import {compareTwoElements} from './vdom'

export const updateQueue = {
  updaters: [], //这里面放着将要执行的更新器对象

  //是否批量更新 如果为true 则直接调用setState不会直接更新 会先暂存起来 到某个时间点再批量更新 反之 则会直接调用updateComponent
  //参看emitUpdate,会在emitUpdate中使用
  isPending: false,

  add(updater) {
    this.updaters.push(updater);
  },

  // 强行全部更新 执行真正的更新
  // 需要有人调用batchUpdate方法才会更新
  batchUpdate(){
    const {updaters} = this;
    let updater;
    while (updater = updaters.pop()/** ←最后setState的最先调用*/){
      updater.updateComponent();
    }
  }
};

class Updater{
  constructor(componentInstance) {
    this.componentInstance = componentInstance; /** 一个Updater和一个类组件实例是一对一的关系*/
    this.pendingStates = []; // 更新可能是批量的 如果处于批量更新的话 需要把分状态先暂存到此数组 最后在真正更新的时候统一合并
    this.nextProps = null; // 新的属性对象 以后会用到
  }
  addState(partialState){
    this.pendingStates.push(partialState); // 不管三七二十一先放进去
    this.emitUpdate(); // 开始视图更新
  }
  emitUpdate(nextProps/** ←这里有值的情况 参看vdom.tsx updateClassComponent*/){
    this.nextProps = nextProps; // ←挂到实例上, 等下updateComponent时会取

    // 如果传递了新的属性对象或则当前非批量更新模式的话就直接更新
    // , 否则先不更新, 先加入到更新队列中
    if(nextProps||!updateQueue.isPending){
      this.updateComponent();
    }else { // 当前是批量更新模式,直接放到 updateQueue 里完事, 直到有人调用updateQueue上的batchUpdate方法才会真正更新
      updateQueue.add(this)
    }
  }
  updateComponent(){
    const {componentInstance, pendingStates, nextProps} = this;
    if (nextProps || pendingStates.length > 0) {
      shouldUpdate(componentInstance, nextProps, this.getState())
    }
  }
  getState(){
    const {componentInstance, pendingStates} = this;
    let {state} = componentInstance;
    if (pendingStates.length > 0) {
      pendingStates.forEach(nextState => {
        if (isFunction(nextState)) { //此时nextState是 this.setState(state=>({number:state.number+1})) 里的state=>({number:state.number+1})
          state = {...state, ...nextState.call(componentInstance, state)};
        }else {
          state = {...state, ...nextState};
        }
      });
    }
    pendingStates.length = 0;
    return state;
  }
}

function shouldUpdate(componentInstance, nextProps, nextState){
  let flag;
  if(componentInstance.shouldComponentUpdate) {
    flag = componentInstance.shouldComponentUpdate(nextProps, nextState);
  }

  /** 不管最终刷不刷新组件,组件的props和state都会发生改变*/
  componentInstance.props = nextProps;
  componentInstance.state = nextState;

  if (!componentInstance.shouldComponentUpdate || (componentInstance.shouldComponentUpdate && flag)) {
    componentInstance.forceUpdate(); // 让组件界面更新
  }

  else if(flag === undefined){
    console.error(`Warning: ${componentInstance.constructor.name}.shouldComponentUpdate(): Returned undefined instead of a boolean value. Make sure to return true or false.`);
  }
}

class Component {
  constructor(props) {
    this.props = props;
    this.$updater = new Updater(this); // this 就是类组件的实例
    this.state = {}; //当前状态
    this.nextProps = null;//下一个属性对象
  }

  setState(partialState){
    console.log('setState');
    this.$updater.addState(partialState);
  }

  // 调用一次forceUpdate 就会导致一次视图刷新
  forceUpdate(){ // 进行组件实际更新
    console.log('forceUpdate');
    const {props, state, renderElement: oldRenderElement} = this;
    if(this.componentWillUpdate){
      this.componentWillUpdate(); // 组件将要更新
    }

    const {getSnapshotBeforeUpdate} = this;
    const extraArgs = getSnapshotBeforeUpdate && getSnapshotBeforeUpdate();

    const newRenderElement = this.render();
    // console.log('oldRenderElement:',oldRenderElement);
    // console.log('newRenderElement:',newRenderElement);
    const currentElement = compareTwoElements(oldRenderElement, newRenderElement);
    this.renderElement = currentElement;
    if (this.componentDidUpdate) {
      this.componentDidUpdate(props, state, extraArgs); // 组件更新完成
    }
  }
}

// 类组件和函数组件编译之后都是函数, 通过此属性来区分到底是函数组件还是类组件
Component.prototype.isReactComponent = {};
export {
  Component
}
